/**
 * 
 */
package unseen.games.ui.manager;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

import unseen.games.config.Config;
import unseen.games.model.Score;
import unseen.games.taptap.MainActivity;
import unseen.games.taptap.R;
import unseen.games.ui.GenericScreenManager;
import unseen.games.ui.adapter.HighScoreAdapter;
import android.content.Context;
import android.os.Build;
import android.provider.Settings.System;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

/**
 * @author PERRAUDIN Steven <sperraudin@neotilus.com>
 *
 * @date 15 juin 2010
 */
public class HighScoreManager extends GenericScreenManager implements OnClickListener{

	private View mHighScoreView;
	private Context mContext;
	
	private String s;
	
	private static FileOutputStream fos;
	private static FileInputStream fis;
	private static DataInputStream dis;
	
	private static final String FILENAME = "mytaptapscores";
	
	private int score;
	
	private boolean isConnected;
	
	private HighScoreAdapter mHighScoreAdapter;
	
	private ListView mHighScoreList;
	
	private EditText mUsername;
	private Button	mSaveScore;
	
	private Button mTabLocal;
	private Button mTabInternet;
	private Button mTabLevel1;
	private Button mTabLevel2;
	private Button mTabLevel3;
		
	private List<Score> mHighScores;
	
	private final int LOCAL 	= 0;
	private final int INTERNET 	= 1;
	
	private final int LEVEL_1 	= 5;
	private final int LEVEL_2 	= 10;
	private final int LEVEL_3 	= 30;
	
	private int TAB				= 0;
	private int SUB_TAB			= 5;
	
	public HighScoreManager(Context context, View view) {
		super(context);
		
		mContext = context;		
		
		mHighScoreAdapter 	= null;
		mHighScores 		= new ArrayList<Score>();
		
		isConnected			= false;
		
		initView(view);
	}

	private void initView(View view) {
		mHighScoreView 	= view;
		
		mHighScoreList 	= (ListView) mHighScoreView.findViewById(R.id.high_score_view);
		mHighScoreList.setEmptyView(mHighScoreView.findViewById(R.id.empty));
		
		mUsername 		= (EditText) mHighScoreView.findViewById(R.id.save_score);
		mUsername.setOnKeyListener(mOnKeyEnterListener);
		
		mSaveScore 		= (Button) mHighScoreView.findViewById(R.id.save_score_button);
		mSaveScore.setOnClickListener(this);
		
		mTabLocal		= (Button) mHighScoreView.findViewById(R.id.high_score_tab_local);
		mTabLocal.setOnClickListener(this);
		
		mTabInternet	= (Button) mHighScoreView.findViewById(R.id.high_score_tab_internet);
		mTabInternet.setOnClickListener(this);
		
		mTabLevel1		= (Button) mHighScoreView.findViewById(R.id.high_score_level_1);
		mTabLevel1.setOnClickListener(this);
		
		mTabLevel2		= (Button) mHighScoreView.findViewById(R.id.high_score_level_2);
		mTabLevel2.setOnClickListener(this);
		
		mTabLevel3		= (Button) mHighScoreView.findViewById(R.id.high_score_level_3);
		mTabLevel3.setOnClickListener(this);
		
		mTabLocal.setSelected(true);
		mTabLevel1.setSelected(true);
		
	}
	
	public void showHighScores(int tapScore, boolean save) {
		checkConnectivity();
		
		if(!save){
			mUsername.setVisibility(View.GONE);
			mSaveScore.setVisibility(View.GONE);
		}
		else{
			score = tapScore;
			mUsername.setVisibility(View.VISIBLE);
			mSaveScore.setVisibility(View.VISIBLE);
		}
		
		mHighScores.clear();
		
		Thread t = new Thread() {
			public void run() {
				if(TAB == LOCAL){
	       			loadLocalScores();
				}
	       		else if(TAB == INTERNET){
		           	if(isConnected) {
		           		loadOnlineScores(); 
		           	}
		           	else {
		            }
	       		}
	            mHandler.post(mUpdateList);
			}
		};
		t.start();	
		
	   	hideNoContentMessage(mHighScoreView);

	   	mHighScoreAdapter = new HighScoreAdapter(mContext, R.layout.list_item, mHighScores);
		mHandler.post(new Runnable()
		{
			public void run()
			{
				mHighScoreList.setAdapter(mHighScoreAdapter);
			}
		});
	}

	private void loadLocalScores(){
		Score score;

		try {
			fis 		= mContext.openFileInput(FILENAME);
			dis 		= new DataInputStream(fis);
						
			while(( s = dis.readLine()) != null){
				JSONArray jsonArray = new JSONArray(s);
				for(int i = 0 ; i < jsonArray.length() ; i++){
					JSONObject jo = (JSONObject)jsonArray.get(i);
					score 	= new Score();
					score.setUsername(jo.getString("username"));
					score.setScore(jo.getInt("score"));
					score.setDifficulty(jo.getInt("difficulty"));
					if(score.getDifficulty() == SUB_TAB)
						mHighScores.add(score);
					score = null;
				}
			}		
			
		    fis.close();		
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		} catch (JSONException e) {
			e.printStackTrace();
		}
		
	}
	
	private void saveLocalScore(String username, int score) {
		try {
			int i 		= 0;
			Score s 	= new Score(username, score, Config.TIME_LIMIT);
			mHighScores.add(s);
			mHighScores = Score.sort(mHighScores);

			int size 			= (mHighScores.size() > Config.MAX_TOPSCORE - 1 ? Config.MAX_TOPSCORE : mHighScores.size());
			String[] paramArray = new String[size];
			String jsonParams	= "";

			for(Score sc : mHighScores){	

				jsonParams = new JSONStringer()
				 .object()
				     .key("username").value(sc.getUsername())
				     .key("score").value(sc.getScore())
				     .key("difficulty").value(Config.TIME_LIMIT)
				 .endObject()
				 .toString();
				paramArray[i] = jsonParams;
				i++;
			}
			
			fos = mContext.openFileOutput(FILENAME, Context.MODE_PRIVATE);
			fos.write(("[" + TextUtils.join(", ", paramArray) + "]").getBytes());
			fos.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}
	
	private void loadOnlineScores(){
		if(isConnected){
			String response	= "NO RESPONSE";
			Score s;

			try {
				DefaultHttpClient hc				= new DefaultHttpClient();  
				ResponseHandler <String> res		= new BasicResponseHandler();  
				HttpPost postMethod					= new HttpPost(Config.DISTANT_SERVER + Config.SERVER_LOAD_FILE);  
				List<NameValuePair> nameValuePairs 	= new ArrayList<NameValuePair>(2); 
				
				nameValuePairs.add(new BasicNameValuePair("difficulty",	"" 	+ SUB_TAB));
				
				postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
				response = hc.execute(postMethod,res);
				
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}    
						
			try {
				JSONArray jsonArray = new JSONArray(response);
				mHighScores 		= new ArrayList<Score>();
				for(int i = 0 ; i < jsonArray.length() ; i++){
					JSONObject jo = (JSONObject)jsonArray.get(i);
					s 	= new Score();
					s.setUsername(jo.getString("username"));
					s.setScore(Integer.parseInt(jo.getString("score")));
					mHighScores.add(s);
				}				
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
	}
	
	private boolean saveOnlineScore(String username, int score) {
		mHighScores 	= new ArrayList<Score>();
		String response	= "404";

		if(isConnected){
			try {
				DefaultHttpClient hc				= new DefaultHttpClient();  
				ResponseHandler <String> res		= new BasicResponseHandler();  
				HttpPost postMethod					= new HttpPost(Config.DISTANT_SERVER + Config.SERVER_SAVE_FILE);  
				List<NameValuePair> nameValuePairs 	= new ArrayList<NameValuePair>(2); 
				
				 String jsonParams = new JSONStringer()
			     .object()
			         .key("username").value(username)
			         .key("score").value(score)
			         .key("difficulty").value(Config.TIME_LIMIT)
			         .key("brand").value(Build.BRAND)
			         .key("device").value(Build.DEVICE)
			         .key("model").value(Build.MODEL)
			         .key("product").value(Build.PRODUCT)
			         .key("release").value(Build.VERSION.RELEASE)
			         .key("id").value(System.getString(mContext.getContentResolver(), System.ANDROID_ID))
			         .key("key").value(generateKey("@#@" + username + "-unseen-" + score))
			     .endObject()
			     .toString();
				
				nameValuePairs.add(new BasicNameValuePair("params", jsonParams));
				 
				postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
				response = hc.execute(postMethod,res);

				if(response == "404"){
					Toast mToast = Toast.makeText(mContext, "Error saving scores.", Toast.LENGTH_SHORT);
					mToast.show();
					return false;
				}
				
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return true;
	}
	
	final Runnable mUpdateResults = new Runnable() {
        public void run() {
        	Toast mToast = Toast.makeText(mContext, "Score saved.", Toast.LENGTH_SHORT);
    		mToast.show();
        	updateListInUi();
        }
    };
    
    final Runnable mUpdateList = new Runnable() {
        public void run() {
            updateListInUi();
    		mHighScoreAdapter.notifyDataSetChanged();
        }
    };
    
    final Runnable mNotConnected = new Runnable() {
        public void run() {
        	Toast mToast = Toast.makeText(mContext, "Enable Internet for online scores", Toast.LENGTH_SHORT);
			mToast.show();
        }
    };
    
	protected void updateListInUi() {
		mHighScoreAdapter.setList(mHighScores);
		if(mHighScoreAdapter.mList.isEmpty())
			showNoContentMessage(mHighScoreView);
		mHighScoreAdapter.notifyDataSetChanged();
	}

	private void saveInput() {
		
		final String username = String.valueOf(mUsername.getText()).replaceAll("[:;\n\"\']", "");
		
		Thread t = new Thread() {
            public void run() {
            	saveLocalScore(username, score);
        		saveOnlineScore(username, score);
                mHandler.post(mUpdateResults);
            }
        };
        t.start();		
        
		/////////////////////////////
		
		mUsername.setText("");
		mUsername.setVisibility(View.GONE);
		mSaveScore.setVisibility(View.GONE);
		
		InputMethodManager imm = (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
		imm.hideSoftInputFromWindow(mUsername.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
//		mHighScoreList.invalidate();
		
		/////////////////////////////
        	
		showHighScores(0, false);
	
	}
	
	private String generateKey(String s){
		MessageDigest m;
		try {
			m = MessageDigest.getInstance("SHA-1");
			m.update(s.getBytes(), 0, s.length());
		    return (new BigInteger(1, m.digest()).toString(16));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public void onClick(View v) {
		
		switch(v.getId()){
			case R.id.save_score_button:
				saveInput();				
				break;
			case R.id.high_score_tab_local:				
				if(TAB != LOCAL){
					TAB = LOCAL;
					hideNoContentMessage(mHighScoreView);
					showHighScores(0, false);
					
					mTabLocal.setSelected(true);
					mTabInternet.setSelected(false);
				}
				break;
			case R.id.high_score_tab_internet:				
				if(TAB != INTERNET){
					TAB = INTERNET;					
					hideNoContentMessage(mHighScoreView);
					showHighScores(0, false);
					
					mTabLocal.setSelected(false);
					mTabInternet.setSelected(true);
				}
				break;
			case R.id.high_score_level_1:
				SUB_TAB = LEVEL_1;
				hideNoContentMessage(mHighScoreView);
				showHighScores(0, false);
				
				mTabLevel1.setSelected(true);
				mTabLevel2.setSelected(false);
				mTabLevel3.setSelected(false);
				
				break;
			case R.id.high_score_level_2:
				SUB_TAB = LEVEL_2;
				hideNoContentMessage(mHighScoreView);
				showHighScores(0, false);
				
				mTabLevel1.setSelected(false);
				mTabLevel2.setSelected(true);
				mTabLevel3.setSelected(false);
				
				break;
			case R.id.high_score_level_3:
				SUB_TAB = LEVEL_3;
				hideNoContentMessage(mHighScoreView);
				showHighScores(0, false);
				
				mTabLevel1.setSelected(false);
				mTabLevel2.setSelected(false);
				mTabLevel3.setSelected(true);
				
				break;
		}
	}

	private boolean checkConnectivity(){				
		if ( !MainActivity.getConnectivityUtils().isConnected()  ) {
			isConnected	= false;
			return false;
		}
		isConnected	= true;
		return true;
	}
	
	private OnKeyListener mOnKeyEnterListener = new OnKeyListener() {
		
		@Override
		public boolean onKey(View v, int keyCode, KeyEvent event) {
			if(keyCode == KeyEvent.KEYCODE_ENTER){
				saveInput();				
			}			
			return false;
		}
	};
	
}
